package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.user.modules.models.User;
import cn.wizzer.app.user.modules.models.UserLog;
import cn.wizzer.app.user.modules.models.vo.UserLogVo;
import cn.wizzer.app.user.modules.services.UserLogService;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.page.datatable.DataTableColumn;
import cn.wizzer.framework.page.datatable.DataTableOrder;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.commons.lang3.math.NumberUtils;
import org.nutz.aop.interceptor.async.Async;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.util.NutMap;

import java.util.*;
import java.util.stream.Collectors;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserLogService.class)
public class UserLogServiceImpl extends BaseServiceImpl<UserLog> implements UserLogService {
    public UserLogServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;
    @Inject
    private UserService userService;

    /**
     * 按月分表的dao实例
     */
    protected Map<String, Dao> ymDaos = new HashMap<String, Dao>();

    /**
     * 获取按月分表的Dao实例,即当前日期的dao实例
     *
     * @return
     */
    public Dao logDao() {
        Calendar cal = Calendar.getInstance();
        String key = String.format("%d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1);
        return logDao(key);
    }

    /**
     * 获取特定月份的Dao实例
     *
     * @param key
     * @return
     */
    public Dao logDao(String key) {
        Dao dao = ymDaos.get(key);
        if (dao == null) {
            synchronized (this) {
                dao = ymDaos.get(key);
                if (dao == null) {
                    dao = Daos.ext(this.dao(), key);
                    dao.create(UserLog.class, false);
                    ymDaos.put(key, dao);
                    try {
                        Daos.migration(dao, UserLog.class, true, false);
                    } catch (Throwable e) {
                    }
                }
            }
        }
        return dao;
    }

    @Async
    public void fastInsertLog(UserLog log) {
        logDao().insert(log);
    }

    public NutMap logData(String tableName, int length, int start, int draw, List<DataTableOrder> orders, List<DataTableColumn> columns, Cnd cnd, String linkName) {
        if (logDao(tableName).exists(UserLog.class)) {
            UserLogService logService2 = new UserLogServiceImpl(logDao(tableName));
            return logService2.data(length, start, draw, orders, columns, cnd, null);
        } else
            return this.data(length, start, draw, orders, columns, cnd, null);
    }

    /**
     * 查询日期
     *
     * @param tablaeName 分表名称
     * @param pageNumber 页码
     * @param pageSize   页大小
     * @param cnd        查询条件
     * @return
     */
    public Pagination data(String tablaeName, int pageNumber, int pageSize, Cnd cnd) {
        Pager pager = this.logDao(tablaeName).createPager(pageNumber, pageSize);
        List<UserLog> list = this.logDao(tablaeName).query(this.getEntityClass(), cnd, pager);
        pager.setRecordCount(this.logDao(tablaeName).count(this.getEntityClass(), cnd));
        return new Pagination(pageNumber, pageSize, pager.getRecordCount(), list);
    }

    /**
     * 多月日志条件查询
     *
     * @param date          时间范围
     * @param keyword       用户名或昵称或手机号
     * @param pageOrderName 排序字段名称
     * @param pageOrderBy   排序方式
     * @param pageNumber    页码
     * @param pageSize      页大小
     * @return
     */
    public Pagination data(String[] date, String keyword, String pageOrderName,
                           String pageOrderBy, int pageNumber, int pageSize) {
        String tableName = Times.format("yyyyMM", new Date());
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder countStringBuilder = new StringBuilder();
        //用户map，用户存储分页查询出的日志中的用户，根据key用户id取出用户信息
        Map<String, User> userMap = new HashMap<>();
        User user = null;
        if (Strings.isNotBlank(keyword)) {
            user = userService.fetch(Cnd.where("phone", "=", keyword));
            if(user != null){
                userMap.put(user.getId(), user);
            }
        }
        stringBuilder.append("select ul.* from (");
        countStringBuilder.append("select (");
        if (date == null || date.length == 0) {
            stringBuilder.append(" select * from user_log_" + tableName);
            countStringBuilder.append(" select count(1) from user_log_" + tableName);
            if(user != null){
                Cnd cnd = Cnd.where("userId", "=", user.getId());
                stringBuilder.append(cnd.toString());
                countStringBuilder.append(cnd.toString());
            }
        } else {
            int m1 = NumberUtils.toInt(Times.format("yyyyMM", Times.D(date[0])));
            int m2 = NumberUtils.toInt(Times.format("yyyyMM", Times.D(date[1])));
            if (m1 == m2) {
                stringBuilder.append(" select * from user_log_" + m1);
                countStringBuilder.append(" select count(1) from user_log_" + m1);
                Cnd cnd = Cnd.where("opAt", ">=", Times.d2TS(Times.D(date[0])))
                        .and("opAt", "<=", Times.d2TS(Times.D(date[1])));
                if(user != null){
                    cnd.and("userId", "=", user.getId());
                }
                stringBuilder.append(cnd.toString());
                countStringBuilder.append(cnd.toString());
            } else {
                for (int i = m1; i < m2 + 1; i++) {
                    if (this.dao().exists("user_log_" + i)) {
                        Cnd cnd = Cnd.NEW();
                        if(i == m1){
                            cnd = Cnd.where("opAt", ">=", Times.d2TS(Times.D(date[0])));
                            if(user != null){
                                cnd.and("userId", "=", user.getId());
                            }
                        }else if (i < m2) {
                            if(user != null){
                                cnd = Cnd.where("userId", "=", user.getId());
                            }
                        }else{
                            cnd = Cnd.where("opAt", "<=", Times.d2TS(Times.D(date[1])));
                            if(user != null){
                                cnd.and("userId", "=", user.getId());
                            }
                        }
                        stringBuilder.append(" (select * from user_log_" + i + cnd.toString() + ") ");
                        countStringBuilder.append(" (select count(1) from user_log_" + i + cnd.toString() + ") ");
                        if(this.dao().exists("user_log_" + (i+1)) && i+1 <= m2){
                            stringBuilder.append(" UNION ALL ");
                            countStringBuilder.append(" + ");
                        }
                    }
                }
            }
        }
        stringBuilder.append(") ul order by ul.opAt desc");
        countStringBuilder.append(") ");
        Pagination pagination = dbService.listPage(UserLogVo.class, pageNumber, pageSize, stringBuilder.toString(), countStringBuilder.toString());
        List<UserLogVo> list = pagination.getList(UserLogVo.class);
        //当用户map中无数据时，取出分页出的日志中的用户id进行查询返回用户map
        if(userMap.size() == 0){
            List<String> ids = list.stream().filter(userLogVo -> userLogVo.getUserId() != null)
                    .map(UserLogVo::getUserId).distinct().collect(Collectors.toList());
            if(ids.size() > 0){
                userMap = userService.findByIds(ids);
            }
        }
        if(userMap.size() > 0){
            for (UserLogVo userLogVo : list) {
                if(Strings.isNotBlank(userLogVo.getUserId())){
                    User logUser = userMap.get(userLogVo.getUserId());
                    if(logUser != null){
                        userLogVo.setUserName(logUser.getUserName());
                        userLogVo.setNickName(logUser.getNickName());
                        userLogVo.setPhone(logUser.getPhone());
                    }
                }
            }
        }
        return pagination;
    }

    @Override
    public List<UserLog> queryByLogDate(Cnd cnd) {
        return this.logDao().query(this.getEntityClass(), cnd);
    }
}
